package org.xiaoyu.rpc;


import lombok.extern.slf4j.Slf4j;
import org.xiaoyu.rpc.common.url.URL;
import org.xiaoyu.rpc.remoting.packet.Invocation;
import org.xiaoyu.rpc.remoting.packet.Result;

/**
 * Created By Have
 * 2021/7/12 16:54
 */
@Slf4j
public abstract class AbstractInvoker<T> implements Invoker<T> {
    /**
     * service type
     */
    private final Class<T> type;
    private final Object proxy;
    private final URL url;
    private volatile boolean destroyed = false;
    private volatile boolean available = true;


    public AbstractInvoker(Object proxy, Class<T> type, URL url) {
        this.type = type;
        this.proxy = proxy;
        this.url = url;
    }

    @Override
    public Class<?> getInterface() {
        return this.type;
    }

    @Override
    public Result invoke(Invocation invocation) {
        Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParamTypes(), invocation.getParameters());
        if (log.isDebugEnabled()) {
            log.info("----------------------------------------------------------------");
            log.info("Invoker Result:" + value);
            log.info("----------------------------------------------------------------");
        }
        Result result;
        if (value instanceof Throwable) {
            result = Result.builder()
                    .value(null)
                    .exception((Throwable) value)
                    .build();
        } else {
            result = Result.builder()
                    .value(value)
                    .exception(null)
                    .build();
        }
        return result;
    }

    public abstract Object doInvoke(Object proxy, String methodName, Class<?>[] parameterTypes, Object[] parameters);

    @Override
    public void destroy() {
        this.destroyed = true;
        setAvailable(false);
    }

    public void setAvailable(boolean available) {
        this.available = available;
    }

    public boolean isDestroyed() {
        return this.destroyed;
    }

    @Override
    public boolean isAvailable() {
        return available;
    }

    @Override
    public URL getUrl() {
        return this.url;
    }
}
